﻿using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;

namespace UFE3D
{
    public static class UFOCollectionsExtensions
    {
        public static T TryGetElementAt<T>(this IList<T> collection, int index, bool fallbackFirst = false, bool fallbackLast = false, bool logError = false)
        {
            if (collection.Count == 0)
            {
                return default;
            }

            if (index >= 0 && index < collection.Count)
            {
                return collection[index];
            }
            else if (logError)
            {
                Debug.LogError($"Invalid index : {index}, collection count is : {collection.Count}");
            }

            if (fallbackFirst)
            {
                return collection[0];
            }

            if (fallbackLast)
            {
                return collection[^1];
            }

            return default;
        }

        public static void AddIfNotExist<T>(this List<T> collection, T item)
        {
            if (collection.IndexOf(item) == -1)
            {
                collection.Add(item);
            }
        }

        public static void AddIfNotExist<TK, TV>(this Dictionary<TK, TV> dict, TK key, TV val)
        {
            if (dict.ContainsKey(key) == false)
            {
                dict[key] = val;
            }
        }
        
        public static void RemoveIfExist<TK, TV>(this Dictionary<TK, TV> dict, TK key)
        {
            if (dict.ContainsKey(key))
            {
                dict.Remove(key);
            }
        }
        
        public static void FillToLinkedList<T>(this IList<T> collection, LinkedList<T> result)
        {
            result.Clear();
            foreach (var item in collection)
            {
                result.AddLast(item);
            }
        }

        public static LinkedListNode<T> NextCircular<T>(this LinkedListNode<T> current)
        {
            return current.Next ?? current.List.First;
        }
        
        public static LinkedListNode<T> PreviousCircular<T>(this LinkedListNode<T> current)
        {
            return current.Previous ?? current.List.Last;
        }
        
        public static bool IsFullEqualIgnoreOrder<T>(IList<T> composeTags, IList<T> existTags)
        {
            if (composeTags.Count != existTags.Count)
            {
                return false;
            }

            bool anyTagNotExist = false;
            for (int i = 0; i < existTags.Count; i++)
            {
                var a = existTags[i];
                var foundInB = false;
                for (int j = 0; j < composeTags.Count; j++)
                {
                    var b = composeTags[j];
                    if (a.Equals(b))
                    {
                        foundInB = true;
                        break;
                    }
                }

                if (!foundInB)
                {
                    anyTagNotExist = true;
                    break;
                }
            }

            if (anyTagNotExist)
            {
                return false;
            }

            return true;
        }

        public static void FindResult<T>(this IList<T> source, IList<T> result, Predicate<T> predicate)
        {
            result.Clear();
            for (int i = 0; i < source.Count; i++)
            {
                if (predicate(source[i]))
                {
                    result.Add(source[i]);
                }
            }
        }
        
        public static List<T> Shuffle<T>(this List<T> list) {
            for ( var i = list.Count - 1; i > 0; i-- ) {
                var j = (int)Mathf.Floor(Random.value * ( i + 1 ));
                var temp = list[i];
                list[i] = list[j];
                list[j] = temp;
            }
            return list;
        }
        
        public static void Shuffle<T>(this T[] array)
        {
            for (int i = 0; i < array.Length; ++i)
            {
                var randIdx = Random.Range(0, array.Length);
                var temp = array[randIdx];
                array[randIdx] = array[i];
                array[i] = temp;
            }
        }
    }
}